package com.fjh.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Snowflake;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fjh.constant.QueueConstant;
import com.fjh.domain.*;
import com.fjh.dto.OrderConfirmDto;
import com.fjh.feign.OrderCartFeign;
import com.fjh.feign.OrderProductFeign;
import com.fjh.feign.OrderUserAddrFeign;
import com.fjh.model.*;
import com.fjh.service.OrderItemService;
import com.fjh.service.OrderService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjh.mapper.OrderMapper;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderUserAddrFeign orderUserAddrFeign;

    @Autowired
    private OrderProductFeign orderProductFeign;

    @Autowired
    private OrderCartFeign orderCartFeign;

    @Autowired
    private Snowflake snowflake;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private OrderItemService orderItemService;

    /**
     * 查询用户的订单状态数量
     * @param userId
     * @return
     */
    @Override
    public OrderStatus getUserOrderCount(String userId) {
        //查询当前用户的订单
        Integer unPay = orderMapper.selectCount(new LambdaQueryWrapper<Order>()
                .eq(Order::getUserId, userId)
                .eq(Order::getStatus, 1)
        );
        Integer payed = orderMapper.selectCount(new LambdaQueryWrapper<Order>()
                .eq(Order::getUserId, userId)
                .eq(Order::getStatus, 2)
        );
        Integer consignment = orderMapper.selectCount(new LambdaQueryWrapper<Order>()
                .eq(Order::getUserId, userId)
                .eq(Order::getStatus, 3)
        );
        return OrderStatus.builder().unPay(unPay).payed(payed).consignment(consignment).build();
    }

    /**
     * 订单的确认
     *1.获取用户的默认收货地址
     * 2.判断来源
     *      1.购物车进来  拿到basketIds  查询购物车表  组装商品的信息
     *      2.商品进来  拿到skuId ，查询商品信息
     * @param userId
     * @param orderConfirmDto
     * @return
     */
    @Override
    public OrderVo orderConfim(String userId, OrderConfirmDto orderConfirmDto) {
        OrderVo orderVo = new OrderVo();
        //获取用户的默认收货地址
        //远程调用获取用户的默认收货地址
        UserAddr userDefaultAddr = orderUserAddrFeign.getUserDefaultAddr(userId);
        orderVo.setUserAddr(userDefaultAddr);
        //拿到购物车ids集合
        List<Long> basketIds = orderConfirmDto.getBasketIds();
        if (CollectionUtils.isEmpty(basketIds)){
            //说明是从商品进来确认订单的
            productToConfim(orderVo,orderConfirmDto.getOrderItem());
        }else {
            //从购物车进来确认订单的
            cartToConfirm(orderVo, basketIds);
        }
        return orderVo;
    }

    /**
     * 下预订单
     * 步骤
     * 1.生成订单号
     * 2.清空购物车
     * 3.减mysql的库存
     * 4.减es的库存
     * 5.写订单表(order  orderItem  orderSettlement)
     * 6.给用户发送消息通知
     * 7.积分处理-----建议在订单完成以后再做
     * 8写延迟队列  30分钟
     * @param userId
     * @param orderVo
     * @return
     */
    @Override
    public String orderSubmit(String userId, OrderVo orderVo) {
        //创建订单号
        String orderNum = createOrderSn();
        //清空购物车
        clearCart(userId,orderVo.getShopCartOrders());
        //减mysql的库存   因为不能判断来源，所以我们使用userId和skuId来进行购物车的清除
        StockChange stockChange = changeStock(orderVo.getShopCartOrders());
        //减es的库存
        changeEsStock(stockChange.getEsChanges());
        //写订单表
        Map<String, String> map = writeOrder(stockChange.getSkuChanges(), orderNum, userId, orderVo);
        //给用户发送通知
        sendWxMsg(userId,map);
        //写延迟队列
        writeMsQueue(orderNum);

        return orderNum;
    }

    /**
     * 写延迟队列
     * @param orderNum
     */
    private void writeMsQueue(String orderNum) {
        rabbitTemplate.convertAndSend(QueueConstant.ORDER_MS_QUEUE,orderNum);
    }

    /**
     * 发送微信通知
     * @param userId
     * @param map
     */
    private void sendWxMsg(String userId, Map<String, String> map) {
        //组装微信消息对象
        WxModel wxModel = new WxModel();
        //todo

    }

    /**
     * 写订单表
     * @param skuChanges
     * @param orderNum
     * @param userId
     * @param orderVo  前台传入的金额一定不能使用，需要自己重新计算
     */
    private Map<String,String> writeOrder(List<SkuChange> skuChanges, String orderNum, String userId, OrderVo orderVo) {
        HashMap<String, String> map = new HashMap<>();
        //拿到skuCHange里面的skuId
        List<Long> skuIds = skuChanges.stream()
                .map(SkuChange::getSkuId)
                .collect(Collectors.toList());
        //远程调用拿到sku
        List<Sku> skuList = orderProductFeign.getSkuListByIds(skuIds);
        if (CollectionUtils.isEmpty(skuList)){
            throw new RuntimeException("服务器维护中");
        }
        //拿到店铺集合
        List<ShopOrderResult> shopCartOrders = orderVo.getShopCartOrders();
        //创建otderItem集合
        ArrayList<OrderItem> orderItems = new ArrayList<>();
        //订单名称拼接
        StringBuilder stringBuilder = new StringBuilder();
        //创建存放单品总金额的集合
        ArrayList<BigDecimal> totalMoneyList = new ArrayList<>();
        //创建存放单品数量的集合
        ArrayList<Integer> countList = new ArrayList<>();

        //循环店铺集合
        shopCartOrders.forEach(shopOrderResult -> {
            //拿到商品条目集合
            List<OrderItem> shopCartItemDiscounts = shopOrderResult.getShopCartItemDiscounts();
            //循环商品条目集合
            shopCartItemDiscounts.forEach(orderItem -> {
                //重新计算价格
                Sku sku1 = skuList.stream()
                        .filter(sku -> sku.getSkuId().equals(orderItem.getSkuId()))
                        .collect(Collectors.toList())
                        .get(0);
                //获取单品数量
                Integer count = orderItem.getProdCount();
                //单品总价
                BigDecimal oneMoney = sku1.getPrice().multiply(new BigDecimal(count));
                //把单品数量添加到集合中
                countList.add(count);
                //添加单品总金额到集合中
                totalMoneyList.add(oneMoney);
                orderItem.setProductTotalAmount(oneMoney);
                orderItem.setPrice(sku1.getPrice());
                //设置一些默认属性
                orderItem.setRecTime(new Date());
                orderItem.setUserId(userId);
                orderItem.setOrderNumber(orderNum);
                orderItem.setShopId(1L);
                orderItem.setCommSts(0);
                orderItems.add(orderItem);
                stringBuilder.append(orderItem.getProdName());
                stringBuilder.append(",");
            });
        });
        //新增orderItem
        boolean flag = orderItemService.saveBatch(orderItems);
        if (flag){
            //新增order表
            StringBuilder orderNameSb = stringBuilder.deleteCharAt(stringBuilder.length() - 1);
            String orderName = orderNameSb.toString();
            BigDecimal totalMoney = totalMoneyList.stream().reduce(BigDecimal::add).get();
            map.put("orderName",orderName);
            map.put("totalMoney",totalMoney.toString());
            Order order = Order.builder()
                    .createTime(new Date())
                    .updateTime(new Date())
                    .userId(userId)
                    .orderNumber(orderName)
                    .prodName(orderName)
                    .deleteStatus(0)
                    .shopId(1L)
                    .remarks(orderVo.getRemarks())
                    .addrOrderId(orderVo.getUserAddr().getAddrId())
                    .isPayed(false)
                    .status(1)
                    .actualTotal(totalMoney.compareTo(new BigDecimal(88)) > 0 ? totalMoney : totalMoney.add(new BigDecimal(6)))  //订单总价
                    .productNums(countList.stream().reduce(Integer::sum).get())
                    .build();
            orderMapper.insert(order);
        }
        return map;
    }

    /**
     * 减少es的库存
     * @param esChanges
     */
    private void changeEsStock(List<EsChange> esChanges) {
        rabbitTemplate.convertAndSend(QueueConstant.PROD_CHANGE_EX,QueueConstant.PROD_CHANGE_KEY, JSON.toJSONString(esChanges));
    }

    /**
     * 减少mysql的库存
     * @param shopCartOrders
     * @return
     */
    private StockChange changeStock(List<ShopOrderResult> shopCartOrders) {
        //创建两个容器    来收集信息
        //prod
        ArrayList<EsChange> esChanges = new ArrayList<>();
        //sku
        ArrayList<SkuChange> skuChanges = new ArrayList<>();

        shopCartOrders.forEach(shopOrderResult -> {
            //拿到商品的信息集合
            List<OrderItem> shopCartItemDiscounts = shopOrderResult.getShopCartItemDiscounts();
            //循环商品
            shopCartItemDiscounts.forEach(orderItem -> {
                Long prodId = orderItem.getProdId();
                Long skuId = orderItem.getSkuId();
                Integer prodCount = orderItem.getProdCount();
                //处理sku
                SkuChange skuChange = new SkuChange(skuId, prodCount * -1);
                skuChanges.add(skuChange);
                //处理prod  如果prod相同  只去累加数量
                List<EsChange> esChangeList = esChanges.stream()
                        .filter(esChange -> esChange.getProdId().equals(prodId))
                        .collect(Collectors.toList());
                if (ObjectUtils.isEmpty(esChangeList)){
                    EsChange esChange = new EsChange(prodId, prodCount * -1);
                    esChanges.add(esChange);
                }else {
                    EsChange esChange = esChangeList.get(0);
                    esChange.setCount(esChange.getCount() - prodCount);
                }
            });
        });

        //组装数据
        StockChange stockChange = new StockChange();
        stockChange.setEsChanges(esChanges);
        stockChange.setSkuChanges(skuChanges);
        //发起远程调用
        orderProductFeign.changeStock(stockChange);
        return stockChange;
    }

    /**
     * 清空购物车
     * @param userId
     * @param shopCartOrders
     */
    private void clearCart(String userId, List<ShopOrderResult> shopCartOrders) {
        //拿到skuIds的集合
        ArrayList<Long> allSkuIds = new ArrayList<>();
        //循环店铺集合
        shopCartOrders.forEach(shopOrderResult -> {
            List<OrderItem> shopCartItemDiscounts = shopOrderResult.getShopCartItemDiscounts();
            List<Long> skuIds = shopCartItemDiscounts.stream()
                    .map(OrderItem::getSkuId)
                    .collect(Collectors.toList());
        });
        //远程调用购物车模块
        orderCartFeign.clearCart(allSkuIds,userId);
    }

    /**
     * 雪花算法创建订单号
     * @return
     */
    private String createOrderSn() {
        return snowflake.nextIdStr();
    }

    /**从购物车进来确认订单的
     * 1.远程调用购物车的模块  根据basketIds  查询购物车的集合
     * 2.拿到skuIds  远程调用商品模块   拿到sku集合
     *3.计算价格
     * 4.循环组装对象
     *
     * @param orderVo
     * @param basketIds
     */
    private void cartToConfirm(OrderVo orderVo, List<Long> basketIds) {
        //.远程调用购物车的模块  根据basketIds  查询购物车的集合
        List<Basket> basketList = orderCartFeign.getBasketListByIds(basketIds);
        if (CollectionUtils.isEmpty(basketList)){
            log.error("远程调用购物车的模块失败");
            throw new RuntimeException("服务器维护中");
        }
        //拿到skuId
        List<Long> skuIds = basketList.stream()
                .map(Basket::getSkuId)
                .collect(Collectors.toList());
        //远程调用商品模块  拿到sku集合
        List<Sku> skuList = orderProductFeign.getSkuListByIds(skuIds);
        if (CollectionUtils.isEmpty(skuList)){
            log.error("远程调用商品的模块 查询sku集合失败了");
            throw new RuntimeException("服务器维护中");
        }
        //创建一个存放单品总价的集合
        ArrayList<BigDecimal> totalMoneyList = new ArrayList<>();
        //创建存放订单条目的集合
        ArrayList<OrderItem> orderItems = new ArrayList<>(basketList.size());
        //计算总金额
        basketList.forEach(basket -> {
            //过滤出来符合的sku
            Sku sku1 = skuList.stream()
                    .filter(sku -> sku.getSkuId().equals(basket.getSkuId()))
                    .collect(Collectors.toList())
                    .get(0);
            //计算单个商品的总价
            BigDecimal oneMoney = sku1.getPrice().multiply(new BigDecimal(basket.getBasketCount()));
            //创建商品条目的对象
            OrderItem orderItem = new OrderItem();
            //对象拷贝
            BeanUtil.copyProperties(sku1,orderItem,true);
            //赋值其他属性
            orderItem.setProdCount(basket.getBasketCount());
            orderItem.setProductTotalAmount(oneMoney);
            orderItems.add(orderItem);
        });
        //组装orderVo
        BigDecimal totalMoney = totalMoneyList.stream()
                .reduce(BigDecimal::add)
                .get();
        orderVo.setTotal(totalMoney);
        orderVo.setShopReduce(BigDecimal.ZERO);
        if (totalMoney.compareTo(new BigDecimal(88))>0){
            //包邮
            orderVo.setActualTotal(totalMoney);
            orderVo.setTransfee(BigDecimal.ZERO);
        }else {
            orderVo.setActualTotal(totalMoney.add(new BigDecimal(6)));
            orderVo.setTransfee(new BigDecimal(6));
        }
        //计算该订单中商品的总数
        Integer count = basketList.stream()
                .map(Basket::getBasketCount)
                .reduce(Integer::sum).get();
        orderVo.setTotalCount(count);
        //创建一个店铺集合
        ArrayList<ShopOrderResult> shopOrderResults = new ArrayList<>();
        //创建一个店铺
        ShopOrderResult shopOrderResult = new ShopOrderResult();
        //设置店铺中订单的条目集合
        shopOrderResult.setShopCartItemDiscounts(orderItems);
        //将店铺对象放入店铺集合
        shopOrderResults.add(shopOrderResult);
        orderVo.setShopCartOrders(shopOrderResults);
    }

    /**
     * 从商品进来确认订单的
     * 需要条目集合
     * 总金额
     * 数量
     * 运费
     * @param orderVo
     * @param orderItem
     */
    private void productToConfim(OrderVo orderVo, OrderItem orderItem) {
        //核心是要获得商品信息
        Long skuId = orderItem.getSkuId();
        //远程调用商品模块  获取sku对象
        List<Sku> skuList = orderProductFeign.getSkuListByIds(Arrays.asList(skuId));
        if (CollectionUtils.isEmpty(skuList)){
            log.error("远程调用商品模块   获取sku对象失败");
            throw new RuntimeException("服务器维护中");
        }
        Sku sku = skuList.get(0);
        //计算价格
        BigDecimal totalMoney = sku.getPrice().multiply(new BigDecimal(orderItem.getProdCount()));
        //对象拷贝
        BeanUtil.copyProperties(sku,orderItem,true);
        //运费
        if (totalMoney.compareTo(new BigDecimal(88))>0){
            //包邮
            orderVo.setActualTotal(totalMoney);
            orderVo.setTransfee(BigDecimal.ZERO);
        }else {
            //有运费
            orderVo.setActualTotal(totalMoney.add(new BigDecimal(6)));
            orderVo.setTransfee(BigDecimal.valueOf(6));
        }
        //商品总数量
        orderVo.setTotalCount(orderItem.getProdCount());
        //商城满减
        orderVo.setShopReduce(BigDecimal.ZERO);
        //创建店铺集合
        ArrayList<ShopOrderResult> shopOrderResults = new ArrayList<>();
        //创建店铺集合
        ShopOrderResult shopOrderResult = new ShopOrderResult();
        //创建商品条目集合
        ArrayList<OrderItem> orderItems = new ArrayList<>();
        //将商品条目添加到商品条目集合
        orderItems.add(orderItem);
        //将商品条目集合设置到店铺集合
        shopOrderResult.setShopCartItemDiscounts(orderItems);
        //将店铺添加到店铺集合
        shopOrderResults.add(shopOrderResult);
        orderVo.setShopCartOrders(shopOrderResults);
    }
}
